package com.dai.rpc.bean;

import com.dai.rpc.annotation.EnableHttpClient;
import com.dai.rpc.annotation.MyHttpClient;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.util.Assert;

import java.util.Map;
import java.util.Set;

/**
 * 1. ImportBeanDefinitionRegistrar类只能通过其他类@Import的方式来加载，通常是启动类或配置类。
 * 2. 使用@Import，如果括号中的类是ImportBeanDefinitionRegistrar的实现类，则会调用接口方法，将其中要注册的类注册成bean
 * 3. 实现该接口的类拥有注册bean的能力
 */
public class MyBeanDefinitionRegistry implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {

    private Environment environment;

    private ResourceLoader resourceLoader;

    public MyBeanDefinitionRegistry(){}


    @Override
    public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
        // 将MsHttpClient所标识的接口，生成代理类，并且注册到Spring容器中
        Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(EnableHttpClient.class.getCanonicalName());
        // 找到Enable注解，获取其中的basePackage属性，此属性表明了@MsHttpClient所在的包
        Object basePackage = annotationAttributes.get("basePackage");
        if(basePackage != null){
            String base = basePackage.toString();
            // 按照自定义的类型，查找classpath下符合要求的class文件
            ClassPathScanningCandidateComponentProvider scanner = getScanner();
            scanner.setResourceLoader(resourceLoader);
            // 添加对应注解的过滤器
            AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(MyHttpClient.class);
            scanner.addIncludeFilter(annotationTypeFilter);
            // 进行包扫描，扫描找到被@MyHttpClient注解标识的类
            Set<BeanDefinition> candidateComponents = scanner.findCandidateComponents(base);
            for (BeanDefinition candidateComponent : candidateComponents) {

                // 如果路径下的bean定义信息是注解类型的bean定义信息
                if(candidateComponent instanceof AnnotatedBeanDefinition){
                    AnnotatedBeanDefinition annotatedBeanDefinition = (AnnotatedBeanDefinition) candidateComponent;
                    AnnotationMetadata metadata1 = annotatedBeanDefinition.getMetadata();
                    Assert.isTrue(metadata1.isInterface(),"@MyHttpClient必须定义在接口上");
                    // 获取注解属性
                    Map<String, Object> annotationAttributes1 = metadata1.getAnnotationAttributes(MyHttpClient.class.getCanonicalName());
                    //  判断是否value设置了值，value是bean的名称，所以一定要有
                    String beanName = getClientName(annotationAttributes1);
                    assert beanName != null;
                    // 通过FactoryBean生成bean的实例
                    BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(MyHttpClientFactoryBean.class);
                    // 设置FactoryBean实现类中自定义的属性，这里我们设置@MyHttpClient标识的类，用于生成代理实现类
                    beanDefinitionBuilder.addPropertyValue("interfaceClass",metadata1.getClassName());
                    //  拿到bean定义信息
                    registry.registerBeanDefinition(beanName, beanDefinitionBuilder.getBeanDefinition());
                }
            }
        }

    }

    private String getClientName(Map<String, Object> clientAnnotationAttributes) {
        if (clientAnnotationAttributes == null){
            throw new RuntimeException("value必须有值");
        }
        Object value = clientAnnotationAttributes.get("value");
        if (value != null && !value.toString().equals("")){
            return value.toString();
        }
        return null;
    }





    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }
    protected ClassPathScanningCandidateComponentProvider getScanner() {
        return new ClassPathScanningCandidateComponentProvider(false, this.environment) {
            @Override
            protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
                boolean isCandidate = false;
                if (beanDefinition.getMetadata().isIndependent()) {
                    if (!beanDefinition.getMetadata().isAnnotation()) {
                        isCandidate = true;
                    }
                }
                return isCandidate;
            }
        };
    }

}
